#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
文本文件处理器

该模块提供了文本文件的读写和处理功能。

创建时间: 2023-07-12
作者: Python Tools Team
"""

import re
from typing import Optional, Union, Dict, Any, List, Tuple, Callable, Set, Iterator, Pattern
from pathlib import Path
import io
import os
import codecs
import chardet

from modules.logger import LogManager
from modules.exception import exception_handler, FileException
from modules.fileio.file_manager import FileManager


class TextFileHandler:
    """
    文本文件处理器
    
    该类提供了文本文件的读写和处理功能，支持多种格式和选项。
    """
    
    def __init__(self, file_manager: Optional[FileManager] = None, logger=None):
        """
        初始化文本文件处理器
        
        Args:
            file_manager: 文件管理器实例，如果为None则创建新实例
            logger: 日志记录器，如果为None则使用默认日志记录器
        """
        self.file_manager = file_manager or FileManager()
        self.logger = logger or LogManager.get_both_logger(name="text_handler")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def read(self, file_path: Union[str, Path], encoding: str = 'utf-8', 
            errors: str = 'strict') -> str:
        """
        读取文本文件
        
        Args:
            file_path: 文本文件路径
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
        
        Returns:
            str: 文件内容
        
        Raises:
            FileException: 文件不存在或读取失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> content = text_handler.read('example.txt')
            >>> print(content)
        """
        return self.file_manager.read_text(file_path, encoding=encoding, errors=errors)
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def read_lines(self, file_path: Union[str, Path], encoding: str = 'utf-8', 
                 errors: str = 'strict', strip: bool = True) -> List[str]:
        """
        读取文本文件的所有行
        
        Args:
            file_path: 文本文件路径
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
            strip: 是否去除每行首尾的空白字符，默认为True
        
        Returns:
            List[str]: 文件行列表
        
        Raises:
            FileException: 文件不存在或读取失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> lines = text_handler.read_lines('example.txt')
            >>> for line in lines:
            >>>     print(line)
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileException(f"文件不存在: {file_path}")
        
        try:
            with open(file_path, 'r', encoding=encoding, errors=errors) as f:
                if strip:
                    lines = [line.strip() for line in f]
                else:
                    lines = [line.rstrip('\n') for line in f]
        except Exception as e:
            raise FileException(f"读取文件失败: {e}")
        
        self.logger.debug(f"已读取文本文件的所有行: {file_path}")
        return lines
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def read_line_iterator(self, file_path: Union[str, Path], encoding: str = 'utf-8', 
                         errors: str = 'strict', strip: bool = True) -> Iterator[str]:
        """
        读取文本文件的行迭代器
        
        Args:
            file_path: 文本文件路径
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
            strip: 是否去除每行首尾的空白字符，默认为True
        
        Returns:
            Iterator[str]: 文件行迭代器
        
        Raises:
            FileException: 文件不存在或读取失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> for line in text_handler.read_line_iterator('example.txt'):
            >>>     print(line)
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileException(f"文件不存在: {file_path}")
        
        try:
            with open(file_path, 'r', encoding=encoding, errors=errors) as f:
                for line in f:
                    if strip:
                        yield line.strip()
                    else:
                        yield line.rstrip('\n')
        except Exception as e:
            raise FileException(f"读取文件失败: {e}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def write(self, file_path: Union[str, Path], content: str, encoding: str = 'utf-8', 
             errors: str = 'strict', create_dirs: bool = True) -> bool:
        """
        写入内容到文本文件
        
        Args:
            file_path: 文本文件路径
            content: 要写入的内容
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
            create_dirs: 如果父目录不存在，是否创建，默认为True
        
        Returns:
            bool: 写入成功返回True
        
        Raises:
            FileException: 写入失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> text_handler.write('example.txt', 'Hello, World!')
        """
        return self.file_manager.write_text(file_path, content, encoding=encoding, 
                                         errors=errors, create_dirs=create_dirs)
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def write_lines(self, file_path: Union[str, Path], lines: List[str], 
                  encoding: str = 'utf-8', errors: str = 'strict', 
                  create_dirs: bool = True, newline: str = '\n') -> bool:
        """
        写入行列表到文本文件
        
        Args:
            file_path: 文本文件路径
            lines: 要写入的行列表
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
            create_dirs: 如果父目录不存在，是否创建，默认为True
            newline: 行分隔符，默认为'\n'
        
        Returns:
            bool: 写入成功返回True
        
        Raises:
            FileException: 写入失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> lines = ['Line 1', 'Line 2', 'Line 3']
            >>> text_handler.write_lines('example.txt', lines)
        """
        file_path = Path(file_path)
        
        # 确保父目录存在
        if create_dirs:
            file_path.parent.mkdir(parents=True, exist_ok=True)
        
        try:
            with open(file_path, 'w', encoding=encoding, errors=errors) as f:
                for line in lines:
                    f.write(line + newline)
        except Exception as e:
            raise FileException(f"写入文件失败: {e}")
        
        self.logger.debug(f"已写入行列表到文本文件: {file_path}")
        return True
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def append(self, file_path: Union[str, Path], content: str, encoding: str = 'utf-8', 
              errors: str = 'strict', create_if_not_exists: bool = True, 
              create_dirs: bool = True) -> bool:
        """
        追加内容到文本文件
        
        Args:
            file_path: 文本文件路径
            content: 要追加的内容
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
            create_if_not_exists: 如果文件不存在，是否创建，默认为True
            create_dirs: 如果父目录不存在，是否创建，默认为True
        
        Returns:
            bool: 追加成功返回True
        
        Raises:
            FileException: 追加失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> text_handler.append('example.txt', '\nAppended line')
        """
        file_path = Path(file_path)
        
        # 检查文件是否存在
        if not file_path.exists() and not create_if_not_exists:
            raise FileException(f"文件不存在: {file_path}")
        
        # 确保父目录存在
        if create_dirs:
            file_path.parent.mkdir(parents=True, exist_ok=True)
        
        try:
            with open(file_path, 'a', encoding=encoding, errors=errors) as f:
                f.write(content)
        except Exception as e:
            raise FileException(f"追加内容失败: {e}")
        
        self.logger.debug(f"已追加内容到文本文件: {file_path}")
        return True
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def append_line(self, file_path: Union[str, Path], line: str, encoding: str = 'utf-8', 
                  errors: str = 'strict', create_if_not_exists: bool = True, 
                  create_dirs: bool = True, ensure_newline: bool = True) -> bool:
        """
        追加一行到文本文件
        
        Args:
            file_path: 文本文件路径
            line: 要追加的行
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
            create_if_not_exists: 如果文件不存在，是否创建，默认为True
            create_dirs: 如果父目录不存在，是否创建，默认为True
            ensure_newline: 是否确保在行前添加换行符（如果文件不为空且不以换行符结尾），默认为True
        
        Returns:
            bool: 追加成功返回True
        
        Raises:
            FileException: 追加失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> text_handler.append_line('example.txt', 'New line')
        """
        file_path = Path(file_path)
        
        # 检查文件是否存在
        if not file_path.exists():
            if not create_if_not_exists:
                raise FileException(f"文件不存在: {file_path}")
            return self.write(file_path, line, encoding=encoding, errors=errors, create_dirs=create_dirs)
        
        # 确保父目录存在
        if create_dirs:
            file_path.parent.mkdir(parents=True, exist_ok=True)
        
        try:
            # 检查文件是否以换行符结尾
            if ensure_newline and file_path.stat().st_size > 0:
                with open(file_path, 'rb') as f:
                    f.seek(-1, os.SEEK_END)
                    last_char = f.read(1)
                    needs_newline = last_char != b'\n'
            else:
                needs_newline = False
            
            with open(file_path, 'a', encoding=encoding, errors=errors) as f:
                if needs_newline:
                    f.write('\n')
                f.write(line + '\n')
        except Exception as e:
            raise FileException(f"追加行失败: {e}")
        
        self.logger.debug(f"已追加行到文本文件: {file_path}")
        return True
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def insert_line(self, file_path: Union[str, Path], line: str, line_number: int, 
                  encoding: str = 'utf-8', errors: str = 'strict') -> bool:
        """
        在指定行插入内容
        
        Args:
            file_path: 文本文件路径
            line: 要插入的行
            line_number: 插入位置（1表示第一行）
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
        
        Returns:
            bool: 插入成功返回True
        
        Raises:
            FileException: 文件不存在或插入失败时抛出
            ValueError: 行号无效时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> text_handler.insert_line('example.txt', 'Inserted line', 2)
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileException(f"文件不存在: {file_path}")
        
        if line_number < 1:
            raise ValueError(f"无效的行号: {line_number}，行号必须大于等于1")
        
        try:
            # 读取所有行
            with open(file_path, 'r', encoding=encoding, errors=errors) as f:
                lines = f.readlines()
            
            # 插入行
            if line_number > len(lines) + 1:
                line_number = len(lines) + 1
            
            if not line.endswith('\n'):
                line += '\n'
            
            lines.insert(line_number - 1, line)
            
            # 写回文件
            with open(file_path, 'w', encoding=encoding, errors=errors) as f:
                f.writelines(lines)
        except Exception as e:
            raise FileException(f"插入行失败: {e}")
        
        self.logger.debug(f"已在文本文件的第{line_number}行插入内容: {file_path}")
        return True
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def replace_line(self, file_path: Union[str, Path], line: str, line_number: int, 
                   encoding: str = 'utf-8', errors: str = 'strict') -> bool:
        """
        替换指定行的内容
        
        Args:
            file_path: 文本文件路径
            line: 新的行内容
            line_number: 行号（1表示第一行）
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
        
        Returns:
            bool: 替换成功返回True
        
        Raises:
            FileException: 文件不存在或替换失败时抛出
            ValueError: 行号无效时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> text_handler.replace_line('example.txt', 'Replaced line', 2)
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileException(f"文件不存在: {file_path}")
        
        if line_number < 1:
            raise ValueError(f"无效的行号: {line_number}，行号必须大于等于1")
        
        try:
            # 读取所有行
            with open(file_path, 'r', encoding=encoding, errors=errors) as f:
                lines = f.readlines()
            
            # 检查行号是否有效
            if line_number > len(lines):
                raise ValueError(f"行号超出范围: {line_number}，文件只有{len(lines)}行")
            
            # 替换行
            if not line.endswith('\n'):
                line += '\n'
            
            lines[line_number - 1] = line
            
            # 写回文件
            with open(file_path, 'w', encoding=encoding, errors=errors) as f:
                f.writelines(lines)
        except Exception as e:
            if isinstance(e, ValueError):
                raise
            raise FileException(f"替换行失败: {e}")
        
        self.logger.debug(f"已替换文本文件的第{line_number}行: {file_path}")
        return True
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def delete_line(self, file_path: Union[str, Path], line_number: int, 
                  encoding: str = 'utf-8', errors: str = 'strict') -> bool:
        """
        删除指定行
        
        Args:
            file_path: 文本文件路径
            line_number: 行号（1表示第一行）
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
        
        Returns:
            bool: 删除成功返回True
        
        Raises:
            FileException: 文件不存在或删除失败时抛出
            ValueError: 行号无效时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> text_handler.delete_line('example.txt', 2)
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileException(f"文件不存在: {file_path}")
        
        if line_number < 1:
            raise ValueError(f"无效的行号: {line_number}，行号必须大于等于1")
        
        try:
            # 读取所有行
            with open(file_path, 'r', encoding=encoding, errors=errors) as f:
                lines = f.readlines()
            
            # 检查行号是否有效
            if line_number > len(lines):
                raise ValueError(f"行号超出范围: {line_number}，文件只有{len(lines)}行")
            
            # 删除行
            del lines[line_number - 1]
            
            # 写回文件
            with open(file_path, 'w', encoding=encoding, errors=errors) as f:
                f.writelines(lines)
        except Exception as e:
            if isinstance(e, ValueError):
                raise
            raise FileException(f"删除行失败: {e}")
        
        self.logger.debug(f"已删除文本文件的第{line_number}行: {file_path}")
        return True
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def delete_lines(self, file_path: Union[str, Path], start_line: int, end_line: int, 
                    encoding: str = 'utf-8', errors: str = 'strict') -> bool:
        """
        删除指定范围的行
        
        Args:
            file_path: 文本文件路径
            start_line: 起始行号（1表示第一行）
            end_line: 结束行号（包含）
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
        
        Returns:
            bool: 删除成功返回True
        
        Raises:
            FileException: 文件不存在或删除失败时抛出
            ValueError: 行号无效时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> text_handler.delete_lines('example.txt', 2, 4)
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileException(f"文件不存在: {file_path}")
        
        if start_line < 1 or end_line < start_line:
            raise ValueError(f"无效的行号范围: {start_line}-{end_line}")
        
        try:
            # 读取所有行
            with open(file_path, 'r', encoding=encoding, errors=errors) as f:
                lines = f.readlines()
            
            # 调整结束行号
            end_line = min(end_line, len(lines))
            
            # 删除行
            del lines[start_line - 1:end_line]
            
            # 写回文件
            with open(file_path, 'w', encoding=encoding, errors=errors) as f:
                f.writelines(lines)
        except Exception as e:
            if isinstance(e, ValueError):
                raise
            raise FileException(f"删除行范围失败: {e}")
        
        self.logger.debug(f"已删除文本文件的第{start_line}到第{end_line}行: {file_path}")
        return True
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def search_text(self, file_path: Union[str, Path], search_text: str, 
                  case_sensitive: bool = True, encoding: str = 'utf-8', 
                  errors: str = 'strict') -> List[Tuple[int, str]]:
        """
        在文本文件中搜索文本
        
        Args:
            file_path: 文本文件路径
            search_text: 要搜索的文本
            case_sensitive: 是否区分大小写，默认为True
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
        
        Returns:
            List[Tuple[int, str]]: 匹配行的行号和内容列表
        
        Raises:
            FileException: 文件不存在或搜索失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> matches = text_handler.search_text('example.txt', 'hello', case_sensitive=False)
            >>> for line_num, line in matches:
            >>>     print(f"Line {line_num}: {line}")
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileException(f"文件不存在: {file_path}")
        
        matches = []
        
        try:
            with open(file_path, 'r', encoding=encoding, errors=errors) as f:
                for i, line in enumerate(f, 1):
                    if case_sensitive:
                        if search_text in line:
                            matches.append((i, line.rstrip('\n')))
                    else:
                        if search_text.lower() in line.lower():
                            matches.append((i, line.rstrip('\n')))
        except Exception as e:
            raise FileException(f"搜索文本失败: {e}")
        
        return matches
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def search_regex(self, file_path: Union[str, Path], pattern: Union[str, Pattern], 
                    encoding: str = 'utf-8', errors: str = 'strict') -> List[Tuple[int, str, List[str]]]:
        """
        在文本文件中使用正则表达式搜索
        
        Args:
            file_path: 文本文件路径
            pattern: 正则表达式模式或已编译的正则表达式对象
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
        
        Returns:
            List[Tuple[int, str, List[str]]]: 匹配行的行号、内容和捕获组列表
        
        Raises:
            FileException: 文件不存在或搜索失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> matches = text_handler.search_regex('example.txt', r'name: (\w+)')
            >>> for line_num, line, groups in matches:
            >>>     print(f"Line {line_num}: {line}, Name: {groups[0]}")
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileException(f"文件不存在: {file_path}")
        
        # 编译正则表达式
        if isinstance(pattern, str):
            pattern = re.compile(pattern)
        
        matches = []
        
        try:
            with open(file_path, 'r', encoding=encoding, errors=errors) as f:
                for i, line in enumerate(f, 1):
                    line = line.rstrip('\n')
                    match = pattern.search(line)
                    if match:
                        groups = list(match.groups())
                        matches.append((i, line, groups))
        except Exception as e:
            raise FileException(f"正则表达式搜索失败: {e}")
        
        return matches
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def replace_text(self, file_path: Union[str, Path], search_text: str, replace_text: str, 
                   case_sensitive: bool = True, encoding: str = 'utf-8', 
                   errors: str = 'strict') -> int:
        """
        在文本文件中替换文本
        
        Args:
            file_path: 文本文件路径
            search_text: 要搜索的文本
            replace_text: 替换为的文本
            case_sensitive: 是否区分大小写，默认为True
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
        
        Returns:
            int: 替换次数
        
        Raises:
            FileException: 文件不存在或替换失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> count = text_handler.replace_text('example.txt', 'hello', 'hi', case_sensitive=False)
            >>> print(f"替换了{count}处")
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileException(f"文件不存在: {file_path}")
        
        try:
            # 读取文件内容
            with open(file_path, 'r', encoding=encoding, errors=errors) as f:
                content = f.read()
            
            # 替换文本
            if case_sensitive:
                new_content, count = re.subn(re.escape(search_text), replace_text, content)
            else:
                pattern = re.compile(re.escape(search_text), re.IGNORECASE)
                new_content, count = pattern.subn(replace_text, content)
            
            # 写回文件
            with open(file_path, 'w', encoding=encoding, errors=errors) as f:
                f.write(new_content)
        except Exception as e:
            raise FileException(f"替换文本失败: {e}")
        
        self.logger.debug(f"已在文本文件中替换文本，共{count}处: {file_path}")
        return count
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def replace_regex(self, file_path: Union[str, Path], pattern: Union[str, Pattern], 
                    replacement: str, encoding: str = 'utf-8', 
                    errors: str = 'strict', flags: int = 0) -> int:
        """
        在文本文件中使用正则表达式替换
        
        Args:
            file_path: 文本文件路径
            pattern: 正则表达式模式或已编译的正则表达式对象
            replacement: 替换为的文本，可以使用\1, \2等反向引用
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
            flags: 正则表达式标志，如re.IGNORECASE
        
        Returns:
            int: 替换次数
        
        Raises:
            FileException: 文件不存在或替换失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> count = text_handler.replace_regex('example.txt', r'name: (\w+)', r'name: \1 Smith')
            >>> print(f"替换了{count}处")
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileException(f"文件不存在: {file_path}")
        
        try:
            # 读取文件内容
            with open(file_path, 'r', encoding=encoding, errors=errors) as f:
                content = f.read()
            
            # 编译正则表达式
            if isinstance(pattern, str):
                pattern = re.compile(pattern, flags)
            
            # 替换文本
            new_content, count = pattern.subn(replacement, content)
            
            # 写回文件
            with open(file_path, 'w', encoding=encoding, errors=errors) as f:
                f.write(new_content)
        except Exception as e:
            raise FileException(f"正则表达式替换失败: {e}")
        
        self.logger.debug(f"已在文本文件中使用正则表达式替换，共{count}处: {file_path}")
        return count
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def count_lines(self, file_path: Union[str, Path], encoding: str = 'utf-8', 
                  errors: str = 'strict', skip_empty: bool = False) -> int:
        """
        计算文本文件的行数
        
        Args:
            file_path: 文本文件路径
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
            skip_empty: 是否跳过空行，默认为False
        
        Returns:
            int: 行数
        
        Raises:
            FileException: 文件不存在或计算失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> line_count = text_handler.count_lines('example.txt', skip_empty=True)
            >>> print(f"文件有{line_count}行")
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileException(f"文件不存在: {file_path}")
        
        try:
            count = 0
            with open(file_path, 'r', encoding=encoding, errors=errors) as f:
                for line in f:
                    if skip_empty and not line.strip():
                        continue
                    count += 1
        except Exception as e:
            raise FileException(f"计算行数失败: {e}")
        
        return count
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def count_words(self, file_path: Union[str, Path], encoding: str = 'utf-8', 
                  errors: str = 'strict') -> int:
        """
        计算文本文件的单词数
        
        Args:
            file_path: 文本文件路径
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
        
        Returns:
            int: 单词数
        
        Raises:
            FileException: 文件不存在或计算失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> word_count = text_handler.count_words('example.txt')
            >>> print(f"文件有{word_count}个单词")
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileException(f"文件不存在: {file_path}")
        
        try:
            count = 0
            with open(file_path, 'r', encoding=encoding, errors=errors) as f:
                for line in f:
                    words = line.split()
                    count += len(words)
        except Exception as e:
            raise FileException(f"计算单词数失败: {e}")
        
        return count
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def count_chars(self, file_path: Union[str, Path], encoding: str = 'utf-8', 
                  errors: str = 'strict', include_whitespace: bool = True) -> int:
        """
        计算文本文件的字符数
        
        Args:
            file_path: 文本文件路径
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
            include_whitespace: 是否包含空白字符，默认为True
        
        Returns:
            int: 字符数
        
        Raises:
            FileException: 文件不存在或计算失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> char_count = text_handler.count_chars('example.txt', include_whitespace=False)
            >>> print(f"文件有{char_count}个字符（不包含空白字符）")
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileException(f"文件不存在: {file_path}")
        
        try:
            with open(file_path, 'r', encoding=encoding, errors=errors) as f:
                content = f.read()
            
            if not include_whitespace:
                content = ''.join(content.split())
            
            count = len(content)
        except Exception as e:
            raise FileException(f"计算字符数失败: {e}")
        
        return count
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def detect_encoding(self, file_path: Union[str, Path]) -> str:
        """
        检测文本文件的编码
        
        Args:
            file_path: 文本文件路径
        
        Returns:
            str: 检测到的编码
        
        Raises:
            FileException: 文件不存在或检测失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> encoding = text_handler.detect_encoding('example.txt')
            >>> print(f"文件编码为: {encoding}")
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileException(f"文件不存在: {file_path}")
        
        try:
            with open(file_path, 'rb') as f:
                raw_data = f.read(4096)  # 读取前4KB数据进行检测
            
            result = chardet.detect(raw_data)
            encoding = result['encoding']
            
            # 如果检测结果为None，默认使用utf-8
            if encoding is None:
                encoding = 'utf-8'
        except Exception as e:
            raise FileException(f"检测编码失败: {e}")
        
        self.logger.debug(f"检测到文件编码: {encoding}, 文件: {file_path}")
        return encoding
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def convert_encoding(self, file_path: Union[str, Path], target_encoding: str = 'utf-8', 
                       source_encoding: str = None, errors: str = 'strict') -> bool:
        """
        转换文本文件的编码
        
        Args:
            file_path: 文本文件路径
            target_encoding: 目标编码，默认为utf-8
            source_encoding: 源编码，如果为None则自动检测
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
        
        Returns:
            bool: 转换成功返回True
        
        Raises:
            FileException: 文件不存在或转换失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> text_handler.convert_encoding('example.txt', 'utf-8', 'gbk')
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileException(f"文件不存在: {file_path}")
        
        try:
            # 如果未指定源编码，则自动检测
            if source_encoding is None:
                source_encoding = self.detect_encoding(file_path)
            
            # 读取文件内容
            with open(file_path, 'r', encoding=source_encoding, errors=errors) as f:
                content = f.read()
            
            # 写入新编码的文件
            with open(file_path, 'w', encoding=target_encoding, errors=errors) as f:
                f.write(content)
        except Exception as e:
            raise FileException(f"转换编码失败: {e}")
        
        self.logger.debug(f"已将文件编码从{source_encoding}转换为{target_encoding}: {file_path}")
        return True
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def split_file(self, file_path: Union[str, Path], output_dir: Union[str, Path], 
                 lines_per_file: int, encoding: str = 'utf-8', 
                 errors: str = 'strict', prefix: str = 'part_') -> List[Path]:
        """
        将文本文件拆分为多个小文件
        
        Args:
            file_path: 文本文件路径
            output_dir: 输出目录
            lines_per_file: 每个文件的行数
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
            prefix: 输出文件名前缀，默认为'part_'
        
        Returns:
            List[Path]: 生成的文件路径列表
        
        Raises:
            FileException: 文件不存在或拆分失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> files = text_handler.split_file('large.txt', 'output', 1000)
            >>> print(f"拆分为{len(files)}个文件")
        """
        file_path = Path(file_path)
        output_dir = Path(output_dir)
        
        if not file_path.exists():
            raise FileException(f"文件不存在: {file_path}")
        
        if lines_per_file <= 0:
            raise ValueError(f"每个文件的行数必须大于0: {lines_per_file}")
        
        # 确保输出目录存在
        output_dir.mkdir(parents=True, exist_ok=True)
        
        output_files = []
        
        try:
            with open(file_path, 'r', encoding=encoding, errors=errors) as f:
                file_count = 0
                line_count = 0
                current_file = None
                
                for line in f:
                    if line_count % lines_per_file == 0:
                        # 关闭上一个文件
                        if current_file is not None:
                            current_file.close()
                        
                        # 创建新文件
                        file_count += 1
                        output_file = output_dir / f"{prefix}{file_count:03d}.txt"
                        current_file = open(output_file, 'w', encoding=encoding, errors=errors)
                        output_files.append(output_file)
                    
                    current_file.write(line)
                    line_count += 1
                
                # 关闭最后一个文件
                if current_file is not None:
                    current_file.close()
        except Exception as e:
            raise FileException(f"拆分文件失败: {e}")
        
        self.logger.debug(f"已将文件拆分为{len(output_files)}个小文件: {file_path}")
        return output_files
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def merge_files(self, file_paths: List[Union[str, Path]], output_path: Union[str, Path], 
                  encoding: str = 'utf-8', errors: str = 'strict', 
                  add_newline: bool = True) -> bool:
        """
        合并多个文本文件
        
        Args:
            file_paths: 要合并的文件路径列表
            output_path: 输出文件路径
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
            add_newline: 是否在每个文件内容后添加换行符，默认为True
        
        Returns:
            bool: 合并成功返回True
        
        Raises:
            FileException: 合并失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> text_handler.merge_files(['part_1.txt', 'part_2.txt'], 'merged.txt')
        """
        output_path = Path(output_path)
        
        # 确保输出文件的父目录存在
        output_path.parent.mkdir(parents=True, exist_ok=True)
        
        try:
            with open(output_path, 'w', encoding=encoding, errors=errors) as out_file:
                for i, file_path in enumerate(file_paths):
                    file_path = Path(file_path)
                    if not file_path.exists():
                        self.logger.warning(f"文件不存在，跳过: {file_path}")
                        continue
                    
                    with open(file_path, 'r', encoding=encoding, errors=errors) as in_file:
                        content = in_file.read()
                        out_file.write(content)
                        
                        # 如果不是最后一个文件且需要添加换行符
                        if add_newline and i < len(file_paths) - 1 and not content.endswith('\n'):
                            out_file.write('\n')
        except Exception as e:
            raise FileException(f"合并文件失败: {e}")
        
        self.logger.debug(f"已合并{len(file_paths)}个文件到: {output_path}")
        return True
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def sort_lines(self, file_path: Union[str, Path], output_path: Union[str, Path] = None, 
                 encoding: str = 'utf-8', errors: str = 'strict', 
                 reverse: bool = False, key: Callable = None) -> bool:
        """
        对文本文件的行进行排序
        
        Args:
            file_path: 文本文件路径
            output_path: 输出文件路径，如果为None则覆盖原文件
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
            reverse: 是否降序排序，默认为False
            key: 排序键函数，默认为None
        
        Returns:
            bool: 排序成功返回True
        
        Raises:
            FileException: 文件不存在或排序失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> text_handler.sort_lines('example.txt', 'sorted.txt')
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileException(f"文件不存在: {file_path}")
        
        if output_path is None:
            output_path = file_path
        else:
            output_path = Path(output_path)
        
        try:
            # 读取所有行
            with open(file_path, 'r', encoding=encoding, errors=errors) as f:
                lines = f.readlines()
            
            # 排序
            lines.sort(reverse=reverse, key=key)
            
            # 写入文件
            with open(output_path, 'w', encoding=encoding, errors=errors) as f:
                f.writelines(lines)
        except Exception as e:
            raise FileException(f"排序行失败: {e}")
        
        self.logger.debug(f"已对文件行进行排序: {file_path} -> {output_path}")
        return True
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def filter_lines(self, file_path: Union[str, Path], output_path: Union[str, Path], 
                    predicate: Callable[[str], bool], encoding: str = 'utf-8', 
                    errors: str = 'strict') -> int:
        """
        根据条件筛选文本文件的行
        
        Args:
            file_path: 文本文件路径
            output_path: 输出文件路径
            predicate: 行筛选条件函数，返回True表示保留该行
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
        
        Returns:
            int: 保留的行数
        
        Raises:
            FileException: 文件不存在或筛选失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> # 筛选包含'error'的行
            >>> count = text_handler.filter_lines('log.txt', 'errors.txt', lambda line: 'error' in line.lower())
            >>> print(f"筛选出{count}行")
        """
        file_path = Path(file_path)
        output_path = Path(output_path)
        
        if not file_path.exists():
            raise FileException(f"文件不存在: {file_path}")
        
        # 确保输出文件的父目录存在
        output_path.parent.mkdir(parents=True, exist_ok=True)
        
        count = 0
        
        try:
            with open(file_path, 'r', encoding=encoding, errors=errors) as in_file, \
                 open(output_path, 'w', encoding=encoding, errors=errors) as out_file:
                for line in in_file:
                    if predicate(line):
                        out_file.write(line)
                        count += 1
        except Exception as e:
            raise FileException(f"筛选行失败: {e}")
        
        self.logger.debug(f"已筛选文件行，保留{count}行: {file_path} -> {output_path}")
        return count
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def remove_duplicates(self, file_path: Union[str, Path], output_path: Union[str, Path] = None, 
                        encoding: str = 'utf-8', errors: str = 'strict', 
                        keep_order: bool = True) -> int:
        """
        移除文本文件中的重复行
        
        Args:
            file_path: 文本文件路径
            output_path: 输出文件路径，如果为None则覆盖原文件
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
            keep_order: 是否保持原始行顺序，默认为True
        
        Returns:
            int: 移除的重复行数
        
        Raises:
            FileException: 文件不存在或处理失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> removed = text_handler.remove_duplicates('example.txt', 'unique.txt')
            >>> print(f"移除了{removed}行重复内容")
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileException(f"文件不存在: {file_path}")
        
        if output_path is None:
            output_path = file_path
        else:
            output_path = Path(output_path)
        
        try:
            # 读取所有行
            with open(file_path, 'r', encoding=encoding, errors=errors) as f:
                lines = [line.rstrip('\n') for line in f]
            
            # 记录原始行数
            original_count = len(lines)
            
            # 移除重复行
            if keep_order:
                seen = set()
                unique_lines = []
                for line in lines:
                    if line not in seen:
                        seen.add(line)
                        unique_lines.append(line)
            else:
                unique_lines = list(set(lines))
                unique_lines.sort(key=lines.index)  # 按原始顺序排序
            
            # 计算移除的行数
            removed_count = original_count - len(unique_lines)
            
            # 写入文件
            with open(output_path, 'w', encoding=encoding, errors=errors) as f:
                for line in unique_lines:
                    f.write(line + '\n')
        except Exception as e:
            raise FileException(f"移除重复行失败: {e}")
        
        self.logger.debug(f"已移除文件中的重复行，共{removed_count}行: {file_path} -> {output_path}")
        return removed_count
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def compare_files(self, file_path1: Union[str, Path], file_path2: Union[str, Path], 
                    encoding: str = 'utf-8', errors: str = 'strict') -> Tuple[List[str], List[str], List[Tuple[int, str, str]]]:
        """
        比较两个文本文件的差异
        
        Args:
            file_path1: 第一个文本文件路径
            file_path2: 第二个文本文件路径
            encoding: 文件编码，默认为utf-8
            errors: 编码错误处理方式，可选'strict', 'ignore', 'replace'等，默认为'strict'
        
        Returns:
            Tuple[List[str], List[str], List[Tuple[int, str, str]]]: 
            (只在文件1中的行, 只在文件2中的行, 不同的行(行号, 文件1中的行, 文件2中的行))
        
        Raises:
            FileException: 文件不存在或比较失败时抛出
        
        Examples:
            >>> text_handler = TextFileHandler()
            >>> only1, only2, diff = text_handler.compare_files('file1.txt', 'file2.txt')
            >>> print(f"只在文件1中: {len(only1)}行")
            >>> print(f"只在文件2中: {len(only2)}行")
            >>> print(f"不同的行: {len(diff)}行")
        """
        file_path1 = Path(file_path1)
        file_path2 = Path(file_path2)
        
        if not file_path1.exists():
            raise FileException(f"文件不存在: {file_path1}")
        
        if not file_path2.exists():
            raise FileException(f"文件不存在: {file_path2}")
        
        try:
            # 读取文件1的行
            with open(file_path1, 'r', encoding=encoding, errors=errors) as f:
                lines1 = [line.rstrip('\n') for line in f]
            
            # 读取文件2的行
            with open(file_path2, 'r', encoding=encoding, errors=errors) as f:
                lines2 = [line.rstrip('\n') for line in f]
            
            # 找出只在文件1中的行
            only_in_1 = [line for line in lines1 if line not in lines2]
            
            # 找出只在文件2中的行
            only_in_2 = [line for line in lines2 if line not in lines1]
            
            # 找出不同的行
            different_lines = []
            for i in range(min(len(lines1), len(lines2))):
                if lines1[i] != lines2[i]:
                    different_lines.append((i + 1, lines1[i], lines2[i]))
        except Exception as e:
            raise FileException(f"比较文件失败: {e}")
        
        return only_in_1, only_in_2, different_lines